package com.heima.media.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.heima.common.aliyun.GreenImageScan;
import com.heima.common.aliyun.GreenTextScan;
import com.heima.common.dto.ResponseResult;
import com.heima.common.enums.AppHttpCodeEnum;
import com.heima.common.minio.service.MinIOService;
import com.heima.common.util.SensitiveWordUtil;
import com.heima.media.dto.ArticleDto;
import com.heima.media.dto.ContentDto;
import com.heima.media.dto.ImageDto;
import com.heima.media.entity.*;
import com.heima.media.feign.ArticleFeign;
import com.heima.media.service.*;
import org.apache.commons.io.IOUtils;
import org.redisson.api.RBlockingQueue;
import org.redisson.api.RBoundedBlockingQueue;
import org.redisson.api.RDelayedQueue;
import org.redisson.api.RedissonClient;
import org.redisson.client.RedisClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.security.smartcardio.SunPCSC;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;

@Service
public class IAuditServiceImpl implements IAuditService {
    @Autowired
    private GreenTextScan greenTextScan;
    @Autowired
    private GreenImageScan greenImageScan;
    @Autowired
    private IWmNewsService wmNewsService;
    @Autowired
    private MinIOService minIOService;
    @Autowired
    private ArticleFeign articleFeign;
    @Autowired
    private IWmUserService wmUserService;
    @Autowired
    private IWmChannelService wmChannelService;
    @Autowired
    private IWmSensitiveService wmSensitiveService;
    @Autowired
    private RedissonClient client; //延迟任务

    /**
     * 自动审核功能
     *
     * @param wmNews
     */
    @Override
    @Async //异步
    public void autoAudit(WmNews wmNews) {
        System.out.println(Thread.currentThread().getName() + "正在执行文章审核...");
        // 如果文章状态为8或4 4是人工审核通过
        if (wmNews.getStatus() == 4 || wmNews.getStatus() == 8) {
            if (System.currentTimeMillis() <= wmNews.getPublishTime().getTime()) {
                sendDelayMessage(wmNews);
            } else {
                saveArticle(wmNews);
            }
            return;
        }
        // 判断自媒体文章的状态,如果状态为1 进入自动审核流程
        if (wmNews.getStatus() == 1) {
            // 审核文本内容,调用阿里云文本审核
            // 提取内容中的文本内容和图片内容
            Map<String, Object> map = getTextAndImageForContent(wmNews);
            String text = (String) map.get("text");
            List<String> images = (List<String>) map.get("images");
            //本地敏感词审核
            Boolean b = textScan(wmNews, text);
            if (!b) return;
            //内容文本检测
            Boolean textResult = textCheck(wmNews, text);
            //内容文本检测失败
            if (!textResult) return;
            // 内容图片
            // 审核图片内容,调用阿里云图片审核
            // 有可能封面图片跟内容图片不一样
            List<ImageDto> coverImages = JSON.parseArray(wmNews.getImages(), ImageDto.class);
            for (ImageDto image : coverImages) {
                if (!images.contains(image.getUrl())) {
                    //若封面图片不是内容里的图片
                    images.add(image.getUrl());
                }
            }
            //审核图片
            Boolean imagesResult = imagesCheck(wmNews, images);
            //图片审核失败
            if (!imagesResult) return;
            //判断是否是延迟发布,判断当前时间是否小于发布时间
            if (wmNews.getPublishTime().getTime()>System.currentTimeMillis()){
                //延迟发布,发布延迟消息
                sendDelayMessage(wmNews);
            }else {
                // 调用文章服务保存文章
                saveArticle(wmNews);
            }
        }
    }

    /**
     * 发送延迟消息
     * @param wmNews
     */
    private void sendDelayMessage(WmNews wmNews) {
        //修改新闻状态为8
        wmNews.setStatus(8);
        wmNewsService.updateById(wmNews);
        //发送延迟消息
        RBlockingQueue<Object> queue = client.getBlockingQueue("publish_article");
        RDelayedQueue<Object> delayedQueue = client.getDelayedQueue(queue);
        //获取时间差-->延迟时间
        Long time = wmNews.getPublishTime().getTime() - System.currentTimeMillis();
        delayedQueue.offer(wmNews,time, TimeUnit.MILLISECONDS);
    }

    /**
     * 保存文章
     * @param wmNews
     */
    private void saveArticle(WmNews wmNews) {
        //创建对象,填充需要的数据
        ArticleDto dto = new ArticleDto();
        BeanUtils.copyProperties(wmNews,dto);
        dto.setId(null);
        //查询频道名称
        WmChannel wmChannel = wmChannelService.getById(wmNews.getChannelId());
        dto.setChannelName(wmChannel.getName());
        dto.setLayout(wmNews.getType());
        dto.setFlag(0);//普通文章
        dto.setCreatedTime(new Date());
        //查询作者信息
        WmUser wmUser = wmUserService.getById(wmNews.getUserId());
        dto.setAuthorId(wmUser.getApAuthorId());
        dto.setAuthorName(wmUser.getName());
        //前端展示是的图片是图片的地址,用逗号隔开
        List<String> list = new ArrayList<>();
        List<ImageDto> imageDtos = JSON.parseArray(wmNews.getImages(), ImageDto.class);
        for (ImageDto imageDto : imageDtos) {
            list.add(imageDto.getUrl());
        }
        //将集合转为字符串用逗号隔开
        String join = String.join(",", list);
        dto.setImages(join);
        //远程调用保存
        ResponseResult<Long> longResponseResult = articleFeign.saveArticle(dto);
        if (longResponseResult.getCode().equals(AppHttpCodeEnum.SUCCESS.getCode())){
            Long articleId = longResponseResult.getData();
            if (articleId != null){
                //将文章id写回到自媒体文章表中
                wmNews.setArticleId(articleId);
                //修改文章表的状态为9
                wmNews.setStatus(9);
                //修改
                wmNewsService.updateById(wmNews);
            }
        }
    }

    /**
     * 图片检测
     *  (已对比)
     * @param wmNews
     * @param images
     * @return
     */
    private Boolean imagesCheck(WmNews wmNews, List<String> images) {
        Boolean flag = false;
        if (images.size() == 0) {
            return true;
        }
        //minio服务部署在内网,需要先下载然后去阿里云审核
        List<byte[]> byteList = new ArrayList<>();
        for (String image : images) {
            if (!StringUtils.isEmpty(image)) {
                InputStream inputStream = minIOService.download(image);
                //流传字节数组
                byte[] bytes = new byte[0];
                try {
                    bytes = IOUtils.toByteArray(inputStream);
                } catch (IOException e) {
                    e.printStackTrace();
                }
                byteList.add(bytes);
            }
        }
        Map map = null;
        try {
            //调用图片检测方法
            map = greenImageScan.imageScan(byteList);
        } catch (Exception e) {
            e.printStackTrace();
        }
        String result = (String) map.get("suggestion");
        switch (result) {
            case "pass":
                flag = true;
                break;
            case "block":
                //审核不通过
                //修改状态为2 //审核失败
                wmNews.setStatus(2);
                // 记录对应的原因
                wmNews.setReason("阿里云图片审核失败: " + map.get("label"));
                wmNewsService.updateById(wmNews);
                break;
            case "review":
                //需要人工审核
                //修改文章的状态
                wmNews.setStatus(3);
                wmNewsService.updateById(wmNews);
                break;
        }
        return flag;

    }

    /**
     * 内容文本检测
     *  (已核对)
     * @param text
     * @return
     */
    private Boolean textCheck(WmNews wmNews, String text) {
        Boolean flag = false;
        String allText = wmNews.getTitle() + wmNews.getLabels() + text;
        try {
            Map map = greenTextScan.greenTextScan(allText);
            //检测后返回的结果判断
            String suggestion = (String) map.get("suggestion");
            if ("pass".equals(suggestion)) {
                //审核通过
                flag = true;
            } else if ("block".equals(suggestion)) {
                //审核不通过
                //修改状态为2 //审核失败
                wmNews.setStatus(2);
                //记录审核失败原因
                wmNews.setReason("阿里云文本审核失败: " + map.get("label"));
                wmNewsService.updateById(wmNews);
            } else if ("review".equals(suggestion)) {
                //需要人工审核
                //修改文章的状态
                wmNews.setStatus(3);
                wmNewsService.updateById(wmNews);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return flag;
    }

    /**
     * 获取内容中的文本及图片
     *  (已核对)
     * @param wmNews
     * @return
     */
    private Map<String, Object> getTextAndImageForContent(WmNews wmNews) {
        Map<String, Object> map = new HashMap<>();
        String content = wmNews.getContent();
        StringBuilder text = new StringBuilder();
        List<String> images = new ArrayList<>();
        List<ContentDto> contentDtos = JSON.parseArray(content, ContentDto.class);
        for (ContentDto contentDto : contentDtos) {
            if ("text".equals(contentDto.getType())) {
                //添加到文本内容
                text.append(contentDto.getValue());
            } else {
                //添加到图片集合
                if (!StringUtils.isEmpty(contentDto.getValue())) {
                    images.add(contentDto.getValue());
                }
            }
        }
        map.put("text", text.toString());
        map.put("images", images);
        return map;
    }

    /**
     * 本地敏感词审核
     * @param wmNews
     * @param text
     * @return
     */
    private Boolean textScan(WmNews wmNews ,String text){
        text = wmNews.getLabels()+wmNews.getTitle()+text;
        if (SensitiveWordUtil.dictionaryMap.size() == 0){
            //初始化数据,
            // 查询数据
            LambdaQueryWrapper<WmSensitive> query = new LambdaQueryWrapper<>();
            query.select(WmSensitive::getSensitives);
            List<String> words = wmSensitiveService.listObjs(query, o->o.toString());
            SensitiveWordUtil.initMap(words);
        }
        //本地敏感词开始审核
        Map<String, Integer> map = SensitiveWordUtil.matchWords(text);
        if (map.size()>0){
            //匹配到敏感词 ,审核不通过
            //修改状态
            wmNews.setStatus(2);
            wmNewsService.updateById(wmNews);
            //给出提示
            Set<String> keys = map.keySet();
            String join = String.join(",", keys);
            System.out.println("内容中包含敏感词:"+join+",审核不通过!!!");
            return false;
        }
        return true;
    }
}
